using System.Collections.Generic;
using UnityEngine;

namespace UIFramework.Core
{
    /// <summary>
    /// 【管理层】
    /// UILayer是UI的管理层，负责一组的Layer控制
    /// UILayer持有多个屏幕控制器实例
    /// </summary>
    /// <typeparam name="TScreen">指定屏幕控制器类型</typeparam>
    public abstract class UILayer<TScreen> : MonoBehaviour where TScreen : IScreenController
    {
        public Dictionary<string, TScreen> registeredScreens;
        
        /// <summary>
        /// 显示界面
        /// </summary>
        /// <param name="screen">界面类型参数</param>
        public abstract void ShowScreen(TScreen screen);

        /// <summary>
        /// 显示界面携带参数
        /// </summary>
        /// <param name="screen">界面类型参数</param>
        /// <param name="props">属性参数</param>
        /// <typeparam name="TProps">属性类型</typeparam>
        public abstract void ShowScreen<TProps>(TScreen screen, TProps props) where TProps : IScreenProperties;

        /// <summary>
        /// 隐藏界面
        /// </summary>
        /// <param name="screen">界面类型参数</param>
        public abstract void HideScreen(TScreen screen);

        /// <summary>
        /// 初始化Layer层
        /// </summary>
        public virtual void Initialize()
        {
            registeredScreens = new Dictionary<string, TScreen>();
        }

        /// <summary>
        /// 根据id找界面controller,并且显示出来
        /// </summary>
        /// <param name="screenId">界面Id</param>
        public void ShowScreenById(string screenId)
        {
            TScreen ctl;
            if (registeredScreens.TryGetValue(screenId, out ctl)) {
                ShowScreen(ctl);
            }
            else {
                Debug.LogError("[AUILayerController] Screen ID" + screenId + " not registered this layer");
            }
        }
        
        /// <summary>
        /// 根据id找界面controller,带上具体的属性参数
        /// </summary>
        /// <param name="screenId">属性Id</param>
        /// <param name="properties">属性参数</param>
        /// <typeparam name="TProps">属性类型</typeparam>
        public void ShowScreenById<TProps>(string screenId, TProps  properties) where TProps : IScreenProperties
        {
            TScreen ctl;
            if (registeredScreens.TryGetValue(screenId, out ctl)) {
                ShowScreen(ctl,  properties);
            }
            else {
                Debug.LogError("[AUILayerController] Screen ID" + screenId + " not registered this layer");
            }
        }
        
        /// <summary>
        /// 根据id找界面controller,隐藏起来
        /// </summary>
        /// <param name="screenId">界面Id</param>
        public void HideScreenById(string screenId)
        {
            TScreen ctl;
            if (registeredScreens.TryGetValue(screenId, out ctl)) {
                HideScreen(ctl);
            }
            else {
                Debug.LogError("[AUILayerController] Could not hide Screen ID" + screenId + " as it is no longer registered");
            }
        }
        
        /// <summary>
        /// 隐藏所有界面
        /// </summary>
        /// <param name="shouldAnimateWhenHidden">隐藏的时候是否需要动画</param>
        public virtual void HideAll(bool shouldAnimateWhenHiding = true)
        {
            foreach (var screen in registeredScreens)
            {
                screen.Value.Hide(shouldAnimateWhenHiding);
            }
        }

        /// <summary>
        /// 根据id查看是否已经注册
        /// </summary>
        /// <param name="screenId">界面id</param>
        /// <returns></returns>
        public bool IsScreenRegistered(string screenId)
        {
            return registeredScreens.ContainsKey(screenId);     
        }

        /// <summary>
        /// 传递进来的界面当作层的子节点
        /// </summary>
        /// <param name="controller">界面的controller</param>
        /// <param name="screenTransform">界面的节点</param>
        public virtual void ReparentScreen(IScreenController controller, Transform screenTransform)
        {
            screenTransform.SetParent(transform, false);
        }

        /// <summary>
        /// 根据id注册界面controller
        /// </summary>
        /// <param name="screenId">界面id</param>
        /// <param name="controller"></param>
        public void RegisterScreen(string screenId, TScreen controller)
        {
            if (!registeredScreens.ContainsKey(screenId))
            {
                ProcessScreenRegister(screenId, controller);
            }
            else
            {
                Debug.LogError("[AUILayer] 屏幕已经注册此ID ：" + screenId);
            }
        }
        
        /// <summary>
        /// 注册方法
        /// </summary>
        /// <param name="screenId"></param>
        /// <param name="controller"></param>
        protected virtual void ProcessScreenRegister(string screenId, TScreen controller)
        {
            controller.ScreenId = screenId;
            registeredScreens.Add(screenId, controller);
            controller.ScreenDestroyed += OnScreenDestroy; // 订阅销毁事件
        }

        /// <summary>
        /// 根据id取消注册界面的controller
        /// </summary>
        /// <param name="screenId"></param>
        /// <param name="controller"></param>
        public void UnregisterScreen(string screenId, TScreen controller)
        {
            if (registeredScreens.ContainsKey(screenId))
            {
                ProcessScreenUnregister(screenId, controller);
            }
            else
            {
                Debug.LogError("[AUILayer] Screen controller not registered for id: ]" + screenId);
            }
        }

        /// <summary>
        /// 取消注册方法
        /// </summary>
        /// <param name="screenId"></param>
        /// <param name="controller"></param>
        protected virtual void ProcessScreenUnregister(string screenId, TScreen controller)
        {
            controller.ScreenDestroyed -= OnScreenDestroy; // 取消订阅销毁事件
            registeredScreens.Remove(screenId);
        }

        /// <summary>
        /// 销毁时调用
        /// </summary>
        /// <param name="screen"></param>
        private void OnScreenDestroy(IScreenController screen)
        {
            if (!string.IsNullOrEmpty(screen.ScreenId)
                && registeredScreens.ContainsKey(screen.ScreenId))
            {
                // 取消注册
                UnregisterScreen(screen.ScreenId, (TScreen) screen);
            }
        }
        
        
    }
}


